#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include "Channel.hpp"
#include <functional>
#include "Task.hpp"

using work_t = std::function<void()>;

enum
{
    OK = 0,
    PIPEERROR,
    FORKERROR
};

class processpool
{
public:
    processpool(int num,work_t tt)
        :processnum(num),
        work(tt)
        {}

    void debug()
    {
        for (auto &c : channels)
        {
            std::cout << c.Name() << std::endl;
        }
    }
    void DispatchTask()
    {
        int who = 0, cnt = 20;
        while (cnt--)
        {
            // 选择任务
            int task = tm.SelectTask();
            // 选择进程 - 轮询选择
            Channel curr(channels[who].WFD(), channels[who].ID());
            who++;
            std::cout << "###########################################" << std::endl;
            std::cout << "father to child " << curr.Name() << " 任务剩余数：" << cnt << std::endl;
            std::cout << "###########################################" << std::endl;
            who %= channels.size();
            // 执行任务
            curr.Send(task);
            sleep(1);
        }
    }

    int InitProceessPool()
    {
        for (int i = 0; i < processnum; i++)
        {
            int fds[2] = {0};
            int n = pipe(fds);
            if (n < 0)
            {
                std::cout << "pipe error" << std::endl;
                return PIPEERROR;
            }
            pid_t id = fork();
            if (id < 0)
            {
                std::cout << "fork error" << std::endl;
                return FORKERROR;
            }
            if (id == 0)
            {
                // 子进程 - read
                close(fds[1]);
                std::cout << "close wfd: ";
                for (auto &c : channels)
                {
                    c.Close();
                    std::cout << c.WFD() << " ";
                }
                std::cout << " over" << std::endl;
                dup2(fds[0], 0);
                work();
                exit(0);
            }
            // 父进程 - write
            close(fds[0]);
            channels.emplace_back(fds[1], id);
        }
        return OK;
    }
    void CleanProcess()
    {
        for (auto &c : channels)
        {
            c.Close();
            pid_t wid = waitpid(c.ID(), nullptr, 0);
            if (wid > 0)
            {
                std::cout << "child " << c.ID() << ", quit success" << std::endl;
            }
        }
        // version 2
        //  for (auto &c : channels)
        //  for (int i = channels.size()-1; i >=0; i--)
        //  {
        //      channels[i].Close();
        //      pid_t wid = waitpid(channels[i].ID(), nullptr, 0);
        //      if (wid > 0)
        //      {
        //          std::cout << "child " << channels[i].ID() << ", quit success" << std::endl;
        //      }
        //  }
        //  version 1
        //  for (auto &c : channels)
        //  {
        //      c.close();
        //  }
        //  for (auto &c : channels)
        //  {
        //      pid_t wid = waitpid(c.ID(), nullptr, 0);
        //      if (wid > 0)
        //      {
        //          std::cout << "child " << c.ID() << ", quit success" << std::endl;
        //      }
        //  }
    }
private:
    std::vector<Channel> channels;
    int processnum;
    work_t work;
};

